﻿using System.Collections.Generic;

namespace Zive.Color {

    public class RgbConversionMatrices {

        public Matrix RgbToXyz;
        public Matrix XyzToRgb;

    }

    public static class RgbConversionMatricesFactory {

        private const double xr = 0.64d; private const double yr = 0.33d;
        private const double xg = 0.30d; private const double yg = 0.60d;
        private const double xb = 0.15d; private const double yb = 0.06d;

        private static readonly Dictionary<Illuminants, RgbConversionMatrices> _rgbXyzMatrixCache;
        private static readonly Matrix XYZ_rgb;

        static RgbConversionMatricesFactory( ) {
            _rgbXyzMatrixCache = new Dictionary<Illuminants, RgbConversionMatrices>( );
            XYZ_rgb = new[ , ] {
                { xr / yr,                xg / yg,                xb / yb               },
                { 1d,                     1d,                     1d                    },
                { ( 1d - xr - yr ) / yr,  ( 1d - xg - yg ) / yg,  ( 1d - xb - yb ) / yb }
            };
        }

        public static RgbConversionMatrices Create( Illuminants illuminant ) {
            //if ( illuminant != Illuminants.D65 ) {
            //    throw new ArgumentException( "RgbConversionMatricesFactory only supports sRGB currently and thus only the D65 illuminant.", "illuminant" );
            //}

            if ( _rgbXyzMatrixCache.ContainsKey( illuminant ) ) {
                return _rgbXyzMatrixCache[ illuminant ];
            }

            Matrix XYZ_W = illuminant.GetReferenceWhite( );
            Matrix S_rgb = XYZ_rgb.Invert( ).Multiply( XYZ_W );

            var result = new RgbConversionMatrices( );
            result.RgbToXyz = new[ , ] {
                { S_rgb[0,0] * XYZ_rgb[0,0], S_rgb[1,0] * XYZ_rgb[0,1], S_rgb[2,0] * XYZ_rgb[0,2] },
                { S_rgb[0,0] * XYZ_rgb[1,0], S_rgb[1,0] * XYZ_rgb[1,1], S_rgb[2,0] * XYZ_rgb[1,2] },
                { S_rgb[0,0] * XYZ_rgb[2,0], S_rgb[1,0] * XYZ_rgb[2,1], S_rgb[2,0] * XYZ_rgb[2,2] }
            };
            result.XyzToRgb = result.RgbToXyz.Invert( );

            _rgbXyzMatrixCache[ illuminant ] = result;
            return result;
        }

    }

}
